import { Node, Vec2, Vec3, v2, v3 } from 'cc';
import { NodeUtil } from 'db://app-game/core/utils/NodeUtil';
import { Vec3Util } from 'db://app-game/core/utils/Vec3Util';
import { ecs } from 'db://app-game/libs/ecs/ECS';
import { ECSEntity } from 'db://app-game/libs/ecs/ECSEntity';
import { smc } from '../../../singleton/SingletonModuleComp';
import { AStar } from 'db://app-game/libs/math/AStar/AStar';

// 1.生成随机点
// 2.计算A星巡逻
// 3.避障移动
// 4.巡逻完成回调
/** 随机移动模型 */
@ecs.register('RandomMoveModel')
export class RandomMoveModelComp extends ecs.Comp {
  /** 移动节点 */
  node: Node = null!;
  /** 地图节点 */
  word: Node = null!;
  /** 巡逻范围 */
  range: Vec2 = new Vec2();
  /** 结束位置 */
  findPos: Vec3 = new Vec3();
  /** 移动速度 */
  speedOfMove: number = 0;
  /** 偏移量 */
  offset: number = 0;
  /** 移动时间 */
  moveTime: number = 0;
  /** 移动完成回调 */
  onComplete: Function | null = null;
  reset(entity: ecs.Entity): void {
    this.node = null!;
    this.word = null!;
    this.range = new Vec2();
    this.findPos = new Vec3();
    this.speedOfMove = 0;
    this.offset = 0;
    this.moveTime = 0;
    this.onComplete = null;
  }
}

/** 移动路径模型 */
@ecs.register('MovePathModel')
export class MovePathModelComp extends ecs.Comp {
  /** 路径索引 */
  pathIndex: number = 0;
  /** 巡逻路径 */
  path: Vec2[] = [];
  /** 是否刷新路径 */
  isRefresh: boolean = false;
  reset(entity: ecs.Entity): void {
    this.pathIndex = 0;
    this.path = [];
    this.isRefresh = false;
  }
}

/** 随机移动系统 */
@ecs.register('RandomMove')
export class RandomMoveSystem
  extends ecs.ComblockSystem<ecs.Entity>
  implements ecs.IEntityEnterSystem, ecs.ISystemUpdate
{
  filter(): ecs.IMatcher {
    return ecs.allOf(RandomMoveModelComp);
  }
  entityEnter(entity: ECSEntity): void {
    const rmm = entity.get(RandomMoveModelComp);
    // 1.生成随机点
    rmm.findPos = this.genRandomPoint(rmm.range, rmm.node, rmm.word);
    // 2.计算A星巡逻路径
    this.resetPath(entity);
  }

  update(entity: ECSEntity, dt: number): void {
    const lmmr = smc.level.LevelMap.LevelMapModelRender;
    const rmm = entity.get(RandomMoveModelComp);
    const mpm = entity.get(MovePathModelComp);

    // 移动结束回调
    if (mpm.pathIndex >= mpm.path.length) {
      this.exit(entity);
      return;
    }

    // 移动方向与移动速度
    const startPos = NodeUtil.posConvert(rmm.node.position, rmm.node, rmm.word);
    // const pathNode = lmmr.graph.getNodePos(mpm.path[mpm.pathIndex]);
    const targetPos = smc.level.LevelMap.tiledPosToCenterPos(mpm.path[mpm.pathIndex]);
    let distance = Vec3.distance(startPos, targetPos);
    if (distance - rmm.offset <= 0) {
      mpm.pathIndex++;
    }
    if (rmm.speedOfMove > 0) {
      const velocity = targetPos.subtract(startPos).normalize();
      let trans = Vec3Util.mul(velocity, rmm.speedOfMove * this.dt);
      rmm.node.translate(trans, Node.NodeSpace.LOCAL);
    }
  }

  /** 重置路径 */
  resetPath(entity: ECSEntity): void {
    // 1.获取开始位置
    const rmm = entity.get(RandomMoveModelComp);
    const startPos = NodeUtil.posConvert(v3(0, 0, 0), rmm.node, rmm.word);
    console.log(startPos, rmm.findPos, rmm.node.position, rmm.node, rmm.word);
    // 2.A星巡逻
    const path = this.genAStarPath(startPos, rmm.findPos);
    const mpm = entity.get(MovePathModelComp) || entity.add(MovePathModelComp);
    mpm.path = path;
    mpm.pathIndex = 0;
  }

  /** 生成随机点 */
  genRandomPoint(range: Vec2, node: Node, word: Node): Vec3 {
    let toPos;
    let isReset = true;
    while (isReset) {
      const pos = node.position;
      const offsetX = Math.floor(Math.random() * range.x * 2) - range.x;
      const offsetY = Math.floor(Math.random() * range.y * 2) - range.y;
      toPos = new Vec3(pos.x + offsetX, pos.y + offsetY, 0);
      toPos = NodeUtil.posConvert(toPos, node, word);
      let gridNode = smc.level.LevelMap.getGraphNode(toPos);
      if (gridNode && !gridNode.isWall()) isReset = false;
    }
    return toPos;
  }

  /** 计算A星路径 */
  genAStarPath(start: Vec3, end: Vec3): Vec2[] {
    const startNode = smc.level.LevelMap.getGraphNode(start);
    const endNode = smc.level.LevelMap.getGraphNode(end);
    const graph = smc.level.LevelMap.LevelMapModelRender.graph;
    const aStar = new AStar(true);
    console.log(start, end, startNode, endNode);
    const path = aStar.moveToward(graph, startNode, endNode);
    return path;
  }

  private exit(e: ecs.Entity) {
    let move = e.get(RandomMoveModelComp);
    move.onComplete?.call(this);
    e.remove(MovePathModelComp);
    e.remove(RandomMoveModelComp);
  }
}
